/******************************************************************************
 * Copyright (C) 2016 Wuhan Water Elephant Co.Ltd All Rights Reserved. 
 * 本软件为武汉水象科技有限公司开发研制。 未经本公司正式书面同意，其他任何个人、
 * 团体不得使用、复制、修改或发布本软件.
 *****************************************************************************/
package com.sxfq.loansupermarket.app.login.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sxfq.loansupermarket.app.constants.AppConstant;
import com.sxfq.loansupermarket.app.dto.AppResponseResult;
import com.sxfq.loansupermarket.business.core.SsoComponent;
import com.sxfq.loansupermarket.business.customer.entity.CustomerBaseInfo;
import com.sxfq.loansupermarket.business.customer.service.CustomerBaseInfoService;
import com.sxfq.loansupermarket.business.dto.login.LoginDto;
import com.sxfq.loansupermarket.business.dto.login.LoginInfoDto;
import com.sxfq.loansupermarket.business.dto.sms.MessageDto;
import com.sxfq.loansupermarket.common.annotation.LockAndSyncRequest;
import com.sxfq.loansupermarket.common.annotation.LoginIntercept;
import com.sxfq.loansupermarket.common.constants.Constants;
import com.sxfq.loansupermarket.common.constants.RedisKeyConstants;
import com.sxfq.loansupermarket.common.utils.AESUtil;
import com.sxfq.loansupermarket.common.utils.ControllerUtil;
import com.sxfq.loansupermarket.common.utils.HttpClientUtil;
import com.sxfq.loansupermarket.common.utils.RedisUtil;

/**
 * 
 * 
 * Module:
 * 
 * LoginController.java
 * 
 * @author 毛恩奇
 * @since JDK 1.8
 * @version 1.0
 * @description: <描述>
 */
@Controller
@RequestMapping("/login")
@LoginIntercept(checkLogin = false)
public class LoginController {
	private Logger logger = Logger.getLogger(LoginController.class);

	@Value("${loanapp_url}${loanapp_login_suffix}")
	private String loanapp_login_url;
	@Value("${loanapp_aes_key}")
	private String loanapp_aes_key;
	// 登录保存时间，单位：秒
	@Value("${sso.seconds:1800}")
	private int seconds;

	/**
	 * 登录token加密
	 */
	@Value("${sso.logintoken_aes_key}")
	private String logintoken_aes_key;
	@Value("${loanapp_url}${loanapp_resetPwd_suffix}")
	private String loanapp_resetPwd_url;
	@Value("${loanapp_url}${loanapp_isSetPwd_suffix}")
	private String loanapp_isSetPwd_url;
	@Value("${loanapp_url}${loanapp_updatePwd_suffix}")
	private String loanapp_updatePwd_url;

	@Resource
	private SsoComponent ssoComponent;
	@Resource
	private CustomerBaseInfoService customerBaseInfoService;

	@RequestMapping(value = "/isLogin")
	@ResponseBody
	public AppResponseResult isLogin(HttpServletRequest request, HttpServletResponse response) {
		AppResponseResult result = AppResponseResult.build(AppConstant.Code.SUCCESS, AppConstant.Msg.SUCCESS);
		String loginToken = null;
		LoginInfoDto loginInfoDto = null;
		String phone = null;
		try {
			loginToken = ControllerUtil.getCookieLoginToken(request, response);
			loginInfoDto = ssoComponent.getLoginInfo(loginToken);
			if (loginInfoDto == null) {
				result.setCode(AppConstant.Code.NOT_LOGIN);
				result.setMsg(AppConstant.Msg.NOT_LOGIN);
				result.setResult(false);
				return result;
			}
			phone = loginInfoDto.getPhone();
		} catch (Exception e) {
			result.setCode(AppConstant.Code.ERROR);
			result.setMsg(AppConstant.Msg.ERROR);
			logger.error("【LoginController.isLogin】异常,phone:" + phone + ",loginToken:" + loginToken, e);
		}
		result.setResult(true);
		return result;
	}

	/**
	 * 登录（密码登录、验证码登录）
	 * 
	 * @param request
	 * @param response
	 * @param loginDto
	 * @return
	 */
	@RequestMapping(value = "/login")
	@ResponseBody
	@LockAndSyncRequest
	public AppResponseResult login(HttpServletRequest request, HttpServletResponse response, LoginDto loginDto) {
		// 登录类型：1.密码登录，2.验证码登录或注册
		Integer loginType = loginDto.getLoginType();
		String phone = loginDto.getPhone();
		String password = loginDto.getPassword();
		String validateCode = loginDto.getValidateCode();
		logger.info("【LoginController.login】phone:" + phone + ",loginDto:" + JSON.toJSONString(loginDto));
		AppResponseResult result = AppResponseResult.build(AppConstant.Code.SUCCESS, "登录成功");
		Map<String, Object> resultMap = new HashMap<String, Object>();
		result.setResult(resultMap);
		if (loginType == null || (loginType != 1 && loginType != 2) || StringUtils.isEmpty(phone)
				|| !phone.matches("^1[1-9]\\d{9}$")) {
			result.setCode(AppConstant.Code.FAIL);
			result.setMsg(AppConstant.Msg.FAIL);
			return result;
		}
		try {
			String redisCodeKey = RedisKeyConstants.SMS_CODE_PRE + "1:" + phone;
			if (loginType == 1) {// 密码登录
				if (StringUtils.isEmpty(password)) {
					result.setCode(AppConstant.Code.FAIL);
					result.setMsg("密码不能为空");
					return result;
				}
			} else if (loginType == 2) {// 验证码登录
				if (StringUtils.isEmpty(validateCode)) {
					result.setCode(AppConstant.Code.FAIL);
					result.setMsg("验证码不能为空");
					return result;
				}

				String redisValidateCode = RedisUtil.get(redisCodeKey);
				if (!validateCode.equals(redisValidateCode)) {
					result.setCode(AppConstant.Code.FAIL);
					result.setMsg("验证码不匹配");
					return result;
				}
			}

			// 调用接口
			Map<String, Object> requestMap = new HashMap<String, Object>();
			requestMap.put("phone", phone);
			requestMap.put("password", password);
			requestMap.put("loginType", loginType);
			requestMap.put("channel", 356);
			requestMap.put("request_data", AESUtil.Encrypt(JSON.toJSONString(requestMap), loanapp_aes_key));
			String responseStr = HttpClientUtil.httpPostRequest(loanapp_login_url, requestMap);
			logger.info("【LoginController.login】phone:" + phone + ",请求app返回" + responseStr);
			AppResponseResult appResult = JSON.parseObject(responseStr, AppResponseResult.class);
			if (appResult == null) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg("系统异常");
				return result;
			}
			if (!AppConstant.Code.SUCCESS.equals(appResult.getCode())) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg(appResult.getMsg());
				return result;
			}
			String appResultEncrypt = AESUtil.Decrypt(JSON.toJSONString(appResult.getResult()), loanapp_aes_key);
			logger.info("【LoginController.login】phone:" + phone + ",请求app返回解密result:" + appResultEncrypt);
			JSONObject appResultJSON = JSON.parseObject(appResultEncrypt);
			// 是否注册(验证码登录，没有借款人则注册)
			Boolean isRegister = appResultJSON.getBoolean("isRegister");
			// 验证码登录时，是否有借款人，没有会创建
			Boolean hasBorrower = appResultJSON.getBoolean("hasBorrower");
			Long borrowerId = appResultJSON.getLong("borrowerId");
			if (isRegister == null || borrowerId == null || hasBorrower == null) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg("系统异常");
				return result;
			}

			if (isRegister) {// 注册发送初始密码短信
				String initPassword = appResultJSON.getString("initPassword");
				MessageDto messageDto = new MessageDto();
				messageDto.setBusinessScenario("1");
				messageDto.setPhone(phone);
				// TODO
				messageDto.setMsg("您好，您已成功注册咿呀口腔，账户为：" + phone + "，密码：" + initPassword + "，为了您的账户安全，请尽快修改密码。");
				messageDto.setType("1");
				String jsonString = JSON.toJSONString(messageDto);
				RedisUtil.rpush(RedisKeyConstants.SMS_SEND, jsonString);
				logger.info("【LoginController.login】注册发送初始密码borrowerId:" + borrowerId + jsonString);
			}

			CustomerBaseInfo customerBaseInfo = new CustomerBaseInfo();
			customerBaseInfo.setBorrowerId(borrowerId);
			customerBaseInfo.setPhone(phone);
			customerBaseInfo.setIdCard(appResultJSON.getString("idCard"));
			customerBaseInfo.setName(appResultJSON.getString("name"));
			customerBaseInfo.setRegisterTime(appResultJSON.getDate("createTime"));
			CustomerBaseInfo responseCustomerBaseInfo = customerBaseInfoService
					.saveOrUpdate4LoginByBorrowerIdOrPhone(customerBaseInfo);

			// 登录成功
			String newLoginToken = null;
			if (seconds <= 0) {// 永久保存，用客户id加密作为token，防止redis冗余
				newLoginToken = AESUtil.Encrypt(responseCustomerBaseInfo.getId().toString(), logintoken_aes_key);
			} else {
				newLoginToken = UUID.randomUUID().toString().replace("-", "");
			}
			ControllerUtil.writeLoginCookie(response, newLoginToken);
			resultMap.put("loginToken", newLoginToken);
			resultMap.put("borrowerId", borrowerId);
			LoginInfoDto loginInfoDto = new LoginInfoDto();
			loginInfoDto.setPhone(phone);
			loginInfoDto.setBorrowerId(borrowerId);
			loginInfoDto.setCustomerBaseId(customerBaseInfo.getId());
			boolean setBool = ssoComponent.setLoginInfo(newLoginToken, loginInfoDto);
			if (!setBool) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg("登录失败");
				return result;
			}
			// 删除redis的验证码
			RedisUtil.del(redisCodeKey);
		} catch (Exception e) {
			result.setCode(AppConstant.Code.ERROR);
			result.setMsg(AppConstant.Msg.ERROR);
			logger.error("【LoginController.login】登录异常,phone:" + phone, e);
		}
		return result;
	}

	/**
	 * 登出
	 * 
	 * @param request
	 * @param response
	 * @param borrowerId
	 * @return
	 */
	@RequestMapping(value = "/loginOut")
	@ResponseBody
	public AppResponseResult loginOut(HttpServletRequest request, HttpServletResponse response, Long borrowerId) {
		AppResponseResult result = AppResponseResult.build(AppConstant.Code.SUCCESS, AppConstant.Msg.SUCCESS);
		try {
			// 登录成功
			String loginToken = ControllerUtil.getCookieLoginToken(request, response);
			ssoComponent.loginOut(loginToken);
			ControllerUtil.delCookie(response, Constants.SSO_COOKIE_ID);
			ControllerUtil.delCookie(response, Constants.BUSINESS_COOKIE_ID);
		} catch (Exception e) {
			result.setCode(AppConstant.Code.ERROR);
			result.setMsg(AppConstant.Msg.ERROR);
			logger.error("【LoginController.loginOut】登出异常,borrowerId:" + borrowerId, e);
		}
		return result;
	}

	/**
	 * 找回密码、重置密码
	 * 
	 * @param request
	 * @param response
	 * @param loginDto
	 * @return
	 */
	@RequestMapping(value = "/resetPwd")
	@ResponseBody
	@LockAndSyncRequest
	public AppResponseResult resetPwd(HttpServletRequest request, HttpServletResponse response, LoginDto loginDto) {
		String phone = loginDto.getPhone();
		String password = loginDto.getPassword();
		String validateCode = loginDto.getValidateCode();
		logger.info("【LoginController.resetPwd】phone:" + phone + ",loginDto:" + JSON.toJSONString(loginDto));
		AppResponseResult result = AppResponseResult.build(AppConstant.Code.SUCCESS, AppConstant.Msg.SUCCESS);
		try {
			if (StringUtils.isEmpty(phone) || !phone.matches("^1[1-9]\\d{9}$") || StringUtils.isEmpty(password)) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg("参数错误");
				return result;
			}
			if (StringUtils.isEmpty(validateCode)) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg("验证码不能为空");
				return result;
			}

			String redisCodeKey = RedisKeyConstants.SMS_CODE_PRE + "2:" + phone;
			String redisValidateCode = RedisUtil.get(redisCodeKey);
			if (!validateCode.equals(redisValidateCode)) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg("验证码不匹配");
				return result;
			}

			// 调用重置密码接口
			Map<String, Object> requestMap = new HashMap<String, Object>();
			requestMap.put("phone", phone);
			requestMap.put("password", password);
			requestMap.put("request_data", AESUtil.Encrypt(JSON.toJSONString(requestMap), loanapp_aes_key));
			String responseStr = HttpClientUtil.httpPostRequest(loanapp_resetPwd_url, requestMap);
			logger.info("【LoginController.resetPwd】phone:" + phone + ",请求app返回" + responseStr);
			AppResponseResult appResult = JSON.parseObject(responseStr, AppResponseResult.class);
			if (appResult == null) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg("系统异常");
				return result;
			}
			if (!AppConstant.Code.SUCCESS.equals(appResult.getCode())) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg(appResult.getMsg());
				return result;
			}

			// 删除redis的验证码
			RedisUtil.del(redisCodeKey);
		} catch (Exception e) {
			result.setCode(AppConstant.Code.ERROR);
			result.setMsg(AppConstant.Msg.ERROR);
			logger.error("【LoginController.resetPwd】重置密码异常,phone:" + phone, e);
		}
		return result;
	}

	/**
	 * 是否设置密码
	 * 
	 * @param request
	 * @param response
	 * @param loginDto
	 * @return
	 */
	@RequestMapping(value = "/isSetPwd")
	@ResponseBody
	@LoginIntercept
	public AppResponseResult isSetPwd(HttpServletRequest request, HttpServletResponse response) {
		AppResponseResult result = AppResponseResult.build(AppConstant.Code.SUCCESS, AppConstant.Msg.SUCCESS);
		String loginToken = ControllerUtil.getCookieLoginToken(request, response);
		LoginInfoDto loginInfo = ssoComponent.getLoginInfo(loginToken);
		String phone = null;
		if (loginInfo != null) {
			phone = loginInfo.getPhone();
		}
		Map<String, Object> resultMap = new HashMap<String, Object>();
		try {
			logger.info("【LoginController.isSetPwd】phone:" + phone + ",loginToken:" + JSON.toJSONString(loginInfo));

			// 调用是否设置密码接口
			Map<String, Object> requestMap = new HashMap<String, Object>();
			requestMap.put("phone", phone);
			requestMap.put("request_data", AESUtil.Encrypt(JSON.toJSONString(requestMap), loanapp_aes_key));
			String responseStr = HttpClientUtil.httpPostRequest(loanapp_isSetPwd_url, requestMap);
			logger.info("【LoginController.isSetPwd】phone:" + phone + ",请求app返回" + responseStr);
			AppResponseResult appResult = JSON.parseObject(responseStr, AppResponseResult.class);
			if (appResult == null) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg("系统异常");
				return result;
			}
			if (!AppConstant.Code.SUCCESS.equals(appResult.getCode())) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg(appResult.getMsg());
				return result;
			}
			String appResultEncrypt = AESUtil.Decrypt(JSON.toJSONString(appResult.getResult()), loanapp_aes_key);
			logger.info("【LoginController.isSetPwd】phone:" + phone + ",请求app返回解密result:" + appResultEncrypt);
			JSONObject appResultJSON = JSON.parseObject(appResultEncrypt);
			resultMap.put("isSetPwd", appResultJSON.getBoolean("isSetPwd"));
		} catch (Exception e) {
			result.setCode(AppConstant.Code.ERROR);
			result.setMsg(AppConstant.Msg.ERROR);
			logger.error("【LoginController.isSetPwd】重置密码异常,phone:" + phone, e);
		}
		result.setResult(resultMap);
		return result;
	}

	/**
	 * 修改密码
	 * 
	 * @param request
	 * @param response
	 * @param loginDto
	 * @return
	 */
	@RequestMapping(value = "/updatePwd")
	@ResponseBody
	@LockAndSyncRequest
	@LoginIntercept
	public AppResponseResult updatePwd(HttpServletRequest request, HttpServletResponse response, LoginDto loginDto) {
		String loginToken = ControllerUtil.getCookieLoginToken(request, response);
		LoginInfoDto loginInfo = ssoComponent.getLoginInfo(loginToken);
		String phone = null;
		if (loginInfo != null) {
			phone = loginInfo.getPhone();
		}
		String oldPassword = loginDto.getOldPassword();
		String password = loginDto.getPassword();
		logger.info("【LoginController.updatePwd】phone:" + phone + ",loginDto:" + JSON.toJSONString(loginDto));
		AppResponseResult result = AppResponseResult.build(AppConstant.Code.SUCCESS, AppConstant.Msg.SUCCESS);
		try {
			if (StringUtils.isEmpty(phone) || !phone.matches("^1[1-9]\\d{9}$") || StringUtils.isEmpty(password)) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg("参数错误");
				return result;
			}

			// 调用修改密码接口
			Map<String, Object> requestMap = new HashMap<String, Object>();
			requestMap.put("phone", phone);
			requestMap.put("oldPassword", oldPassword);
			requestMap.put("password", password);
			requestMap.put("request_data", AESUtil.Encrypt(JSON.toJSONString(requestMap), loanapp_aes_key));
			String responseStr = HttpClientUtil.httpPostRequest(loanapp_updatePwd_url, requestMap);
			logger.info("【LoginController.updatePwd】phone:" + phone + ",请求app返回" + responseStr);
			AppResponseResult appResult = JSON.parseObject(responseStr, AppResponseResult.class);
			if (appResult == null) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg("系统异常");
				return result;
			}
			if (!AppConstant.Code.SUCCESS.equals(appResult.getCode())) {
				result.setCode(AppConstant.Code.FAIL);
				result.setMsg(appResult.getMsg());
				return result;
			}

		} catch (Exception e) {
			result.setCode(AppConstant.Code.ERROR);
			result.setMsg(AppConstant.Msg.ERROR);
			logger.error("【LoginController.resetPwd】重置密码异常,phone:" + phone, e);
		}
		return result;
	}
}